#include "uart_control.h"
#include <rtthread.h>
#include "board.h"
#include "usb_service.h"

static rt_device_t uart_dev = RT_NULL;

static rt_bool_t uart_is_config = RT_FALSE;
static uart_config_t uart_config = {0};

static rt_uint8_t uart_rx_buff[UART_PACK_SIZE] = {0};

static char uart_stack[UART_TASK_STACK_SIZE] = {0};
static struct rt_thread uart_task;
static struct rt_semaphore uart_rx_sem;

static rt_err_t uart_recv_isr(rt_device_t dev, rt_size_t size)
{
    if(size > 0)
    {
        rt_sem_release(&uart_rx_sem);
    }
    return RT_EOK;
}

static void uart2usb_handler(void *param)
{
    rt_uint16_t rx_size = 0;
    for(;;)
    {
        rt_sem_take(&uart_rx_sem, RT_WAITING_FOREVER);
        if(uart_dev)
        {
            rx_size = rt_device_read(uart_dev, 0, uart_rx_buff, UART_PACK_SIZE);
            usb_service_uart2usb(uart_rx_buff, rx_size);
        }
    }
}

void usb2uart_handler(rt_uint8_t *data, rt_uint16_t len)
{
    if(uart_dev)
    {
        rt_device_write(uart_dev, 0, data, len);
    }
}

static void uart_config_set(uart_config_t *config)
{
    if(rt_memcmp(&uart_config, (rt_uint8_t *)config, sizeof(uart_config_t)) != 0)
    {
        rt_memcpy((rt_uint8_t *)&uart_config, config, sizeof(uart_config_t));
        uart_is_config = RT_TRUE;
    }
    if(uart_is_config)
    {
        struct serial_configure serial_config = RT_SERIAL_CONFIG_DEFAULT;
        if(uart_dev != RT_NULL) {
            rt_device_close(uart_dev);
            uart_dev = RT_NULL;
        }
        
        uart_is_config = RT_FALSE;
        uart_dev = rt_device_find(UART_NAME);
        serial_config.baud_rate = uart_config.baudrate;
        serial_config.stop_bits = uart_config.stopbit;
        serial_config.parity = uart_config.parity;
        serial_config.data_bits = uart_config.databit;
        serial_config.bufsz = UART_PACK_SIZE;
        rt_device_control(uart_dev, RT_DEVICE_CTRL_CONFIG, &serial_config);

        rt_device_open(uart_dev, RT_DEVICE_FLAG_DMA_RX);
        rt_device_set_rx_indicate(uart_dev, uart_recv_isr);
    }
}

int uart_control_init(void)
{
    usb_service_usb2uart_reg(usb2uart_handler);
    usb_service_uart_config_reg(uart_config_set);

    rt_sem_init(&uart_rx_sem, "urx_sem", 0, RT_IPC_FLAG_FIFO);

    rt_thread_init(&uart_task,
                   "uart", 
                   uart2usb_handler,
                   RT_NULL,
                   &uart_stack[0],
                   UART_TASK_STACK_SIZE,
                   UART_TASK_PRIORITY,
                   UART_TASK_TIMESLICE);
    rt_thread_startup(&uart_task);

    return RT_EOK;
}
INIT_APP_EXPORT(uart_control_init);
